package com.jn.system.utils.file;

import com.jn.common.config.RuoYiConfig;
import com.jn.common.constant.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;

public class ChunkFileUtils {
    private static final Logger log = LoggerFactory.getLogger(ChunkFileUtils.class);
    // 临时分片目录（不影响最终URL，仅用于临时存储）
    private static final String TEMP_DIR = "temp/";
    // 最终视频存储的相对路径（必须与URL路径完全一致）
    // 注意：这里用固定斜杠"/"，避免系统差异，且末尾不加斜杠
    private static final String VIDEO_RELATIVE_PATH = "video";

    /**
     * 合并分片并生成标准URL（核心修复部分）
     */
    public static String mergeChunks(String fileId, String fileName, Integer totalChunks) throws IOException {
        String chunkDir = getChunkDir(fileId);
        File dir = new File(chunkDir);

        // 校验分片目录
        if (!dir.exists() || !dir.isDirectory()) {
            throw new FileNotFoundException("分片目录不存在: " + chunkDir);
        }

        // 校验分片数量
        File[] chunkFiles = dir.listFiles((d, name) -> name.startsWith(fileId + "-"));
        if (chunkFiles == null || chunkFiles.length != totalChunks) {
            throw new IOException("分片不完整: 找到" + (chunkFiles == null ? 0 : chunkFiles.length) + "个，需要" + totalChunks + "个");
        }

        // 排序分片
        List<File> sortedChunks = new ArrayList<>();
        for (int i = 0; i < totalChunks; i++) {
            File chunkFile = new File(chunkDir + fileId + "-" + i);
            if (!chunkFile.exists()) {
                throw new FileNotFoundException("缺失分片: " + chunkFile.getName());
            }
            sortedChunks.add(chunkFile);
        }

        // -------------------------- 关键修复：文件存储与URL生成 --------------------------
        // 1. 生成唯一文件名（保留扩展名）
        String ext = getFileExtension(fileName); // 如 "mp4"
        String uniqueName = UUID.randomUUID().toString().replaceAll("-", ""); // 移除UUID中的"-"
        String finalFileName = ext.isEmpty() ? uniqueName : (uniqueName + "." + ext); // 如 "b1ba7bcd060b40658eab9ed23f1f4480.mp4"

        // 2. 计算本地存储路径（确保与若依静态映射对齐）
        // 若依上传根路径：如 D:/ruoyi/upload/
        String uploadRoot = RuoYiConfig.getUploadPath();
        // 确保根路径以斜杠结尾（统一格式）
        if (!uploadRoot.endsWith("/") && !uploadRoot.endsWith(File.separator)) {
            uploadRoot += "/";
        }
        // 完整本地路径：根路径 + 相对路径 + 文件名 → D:/ruoyi/upload/upload/video/b1ba7bcd060b40658eab9ed23f1f4480.mp4
        String localFilePath = uploadRoot + VIDEO_RELATIVE_PATH + "/" + finalFileName;

        // 3. 创建存储目录（确保 upload/video 目录存在）
        File saveDir = new File(uploadRoot + VIDEO_RELATIVE_PATH);
        if (!saveDir.exists()) {
            boolean mkdirs = saveDir.mkdirs();
            if (!mkdirs) {
                throw new IOException("无法创建视频存储目录: " + saveDir.getAbsolutePath());
            }
        }

        // 4. 合并文件到本地路径
        try (FileOutputStream out = new FileOutputStream(localFilePath)) {
            byte[] buffer = new byte[1024 * 1024]; // 1MB缓冲区
            for (File chunk : sortedChunks) {
                try (FileInputStream in = new FileInputStream(chunk)) {
                    int len;
                    while ((len = in.read(buffer)) != -1) {
                        out.write(buffer, 0, len);
                    }
                }
            }
        }

        // 5. 清理临时分片
        deleteChunkDir(fileId);
        // 6. 生成标准URL（核心！严格控制格式）
        // 若依静态前缀：如 /profile
        String profilePrefix = RuoYiConfig.getProfile();
        // 确保前缀不以斜杠结尾（避免重复）
        // 最终URL：前缀 + / + 相对路径 + / + 文件名 → /profile/upload/video/b1ba7bcd060b40658eab9ed23f1f4480.mp4
        return Constants.RESOURCE_PREFIX + "/upload/" + VIDEO_RELATIVE_PATH + "/" + finalFileName;
    }

    // -------------------------- 以下为辅助方法（无需修改） --------------------------
    public static String getTempPath() {
        String uploadRoot = RuoYiConfig.getUploadPath();
        if (!uploadRoot.endsWith("/") && !uploadRoot.endsWith(File.separator)) {
            uploadRoot += "/";
        }
        return uploadRoot + TEMP_DIR;
    }

    public static String getChunkDir(String fileId) {
        String tempPath = getTempPath();
        if (!tempPath.endsWith("/")) {
            tempPath += "/";
        }
        return tempPath + fileId + "/";
    }

    public static boolean saveChunk(String fileId, Integer chunkIndex, MultipartFile file) throws IOException {
        String chunkDir = getChunkDir(fileId);
        File dir = new File(chunkDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File chunkFile = new File(chunkDir + fileId + "-" + chunkIndex);
        file.transferTo(chunkFile);
        return true;
    }

    public static void deleteChunkDir(String fileId) {
        String chunkDir = getChunkDir(fileId);
        try {
            Files.walk(Paths.get(chunkDir))
                    .sorted(Comparator.reverseOrder())
                    .map(Path::toFile)
                    .forEach(File::delete);
        } catch (IOException e) {
            log.error("删除分片目录失败: {}", chunkDir, e);
        }
    }

    public static String generateFileId(String fileName, Long fileSize, String fileType) {
        try {
            String source = fileName + fileSize + fileType + System.currentTimeMillis();
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(source.getBytes());
            byte[] bytes = md.digest();
            StringBuilder sb = new StringBuilder();
            for (byte b : bytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            log.error("生成fileId失败", e);
            return UUID.randomUUID().toString().replaceAll("-", "");
        }
    }

    public static String getFileExtension(String fileName) {
        if (fileName == null || !fileName.contains(".")) {
            return "";
        }
        return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
    }

    public static long calcDirectorySize(String directoryPath) {
        File dir = new File(directoryPath);
        if (!dir.exists() || !dir.isDirectory()) {
            return 0;
        }
        long size = 0;
        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                size += file.isFile() ? file.length() : calcDirectorySize(file.getPath());
            }
        }
        return size;
    }
}